package com.jungle.client.control;

import com.jungle.client.event.SaveEvent;
import javafx.collections.ObservableList;
import javafx.event.Event;
import javafx.event.EventHandler;
import javafx.scene.control.TableCell;
import javafx.scene.control.TableColumn;
import javafx.scene.control.TableView;
import javafx.scene.input.DataFormat;
import javafx.scene.input.DragEvent;
import javafx.scene.input.Dragboard;
import javafx.scene.input.TransferMode;
import javafx.util.Callback;
import javafx.util.StringConverter;
import lombok.extern.slf4j.Slf4j;

import java.util.function.BiConsumer;

@Slf4j
public class DraggableTableCell {
    private DraggableTableCell(){}
    public static final DataFormat SERIALIZED_MIME_TYPE = new DataFormat("application/x-java-serialized-object");

    public static <S> Callback<TableColumn<S, String>, TableCell<S, String>> forString(BiConsumer<S, Object> consumer) {
        return forAny(new StringConverter<>() {
            @Override
            public String toString(String object) {
                return object;
            }

            @Override
            public String fromString(String string) {
                return string;
            }
        }, consumer);
    }

    public static <S, T> Callback<TableColumn<S, T>, TableCell<S, T>> forAny(StringConverter<T> converter, BiConsumer<S, Object> consumer) {
        return tableColumn -> new TableCell<>() {
            @Override
            protected void updateItem(T item, boolean empty) {
                super.updateItem(item, empty);
                if (empty) {
                    setGraphic(null);
                } else {
                    setText(converter.toString(item));

                    setOnDragOver(dragOver());

                    int rowIndex = getIndex();

                    TableView<S> tableView = getTableView();
                    // 拖拽结束
                    setOnDragDropped(dragDropped(tableView, rowIndex, consumer));
                }
            }
        };
    }

    private static EventHandler<DragEvent> dragOver() {
        return event -> {
            log.info("onDragOver {}", event);
            Dragboard dragboard = event.getDragboard();
            if (dragboard.hasContent(SERIALIZED_MIME_TYPE)) {
                event.acceptTransferModes(TransferMode.MOVE);
            }
        };
    }

    private static <S> EventHandler<DragEvent> dragDropped(TableView<S> tableView, int rowIndex, BiConsumer<S, Object> consumer) {
        return event -> {
            log.info("onDragDropped {}", event);
            Dragboard dragboard = event.getDragboard();

            Object content = dragboard.getContent(SERIALIZED_MIME_TYPE);

            ObservableList<S> items = tableView.getItems();
            S dataItemVo = items.get(rowIndex);

            consumer.accept(dataItemVo, content);

            //若数据已调置完整，触发保存操作
            Event.fireEvent(tableView, new SaveEvent(rowIndex));
            // 修改行
            items.set(rowIndex, dataItemVo);

            event.consume();
        };
    }
}
